﻿using Consul;
using Extensions.Consul.Entity;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Hosting;
using System;

namespace Extensions.Consul
{
    /// <summary>
    /// Consul 服务治理扩展
    /// </summary>
    public static class AppConsulBuilderExtensions
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="app">中间件管道</param>
        /// <param name="lifetime">应用启动和关闭时对相关组件发送相应的信号或者通知</param>
        /// <param name="serviceEntity">Consul 注册参数</param>
        /// <returns></returns>
        public static IApplicationBuilder RegisterConsul(this IApplicationBuilder app, IHostApplicationLifetime lifetime, ServiceEntity serviceEntity)
        {
            var consulClient = new ConsulClient(x => x.Address = new Uri($"http://{serviceEntity.ConsulIP}:{serviceEntity.ConsulPort}"));//请求注册的 Consul 地址
            var httpCheck = new AgentServiceCheck()
            {
                // 服务启动多久后注册
                DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5),
                // 心跳间隔
                Interval = TimeSpan.FromSeconds(10),
                // 健康检查地址
                HTTP = $"http://{serviceEntity.IP}:{serviceEntity.Port}/api/health",
                // 心跳检查超时时间
                Timeout = TimeSpan.FromSeconds(5)
            };

            // 注册服务到 Consul
            var registration = new AgentServiceRegistration()
            {
                Checks = new[] { httpCheck },
                ID = Guid.NewGuid().ToString(),
                Name = serviceEntity.ServiceName,
                Address = serviceEntity.IP,
                Port = serviceEntity.Port,
                // 添加 urlprefix-/servicename 格式的 tag 标签，以便 Fabio 识别
                Tags = new[] { $"urlprefix-/{serviceEntity.ServiceName}" }
            };

            consulClient.Agent.ServiceRegister(registration).Wait();
            lifetime.ApplicationStopping.Register(() =>
            {
                // 服务停止时取消注册
                consulClient.Agent.ServiceDeregister(registration.ID).Wait();
            });
            return app;
        }
    }
}
